package com.neusoft.elmboot.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.neusoft.elmboot.exception.exceptions.BaseException;
import com.neusoft.elmboot.exception.exceptions.ErrorStateException;
import com.neusoft.elmboot.exception.exceptions.IllegalAmountException;
import com.neusoft.elmboot.mapper.BusinessWalletMapper;
import com.neusoft.elmboot.mapper.WalletMapper;
import com.neusoft.elmboot.po.PlatformRevenue;
import com.neusoft.elmboot.po.dto.BusinessWalletDTO;
import com.neusoft.elmboot.po.wallet.VirtualWallet;
import com.neusoft.elmboot.po.wallet.WalletTransaction;
import com.neusoft.elmboot.service.BusinessWalletService;
import com.neusoft.elmboot.service.WalletService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.crypto.bcrypt.BCrypt;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
@Transactional(rollbackFor = Exception.class)
@Slf4j
public class BusinessWalletServiceImpl extends ServiceImpl<BusinessWalletMapper, PlatformRevenue> implements BusinessWalletService {

    @Resource
    private BusinessWalletMapper businessWalletMapper;

    @Resource
    private WalletMapper walletMapper;

    @Resource
    private WalletService walletService;

    @Resource
    private BCryptPasswordEncoder encoder;

    // 平台手续费：固定1元
    private static final BigDecimal PLATFORM_FEE = BigDecimal.valueOf(1.00);

    @Override
    public BusinessWalletDTO getBusinessWalletInfo(String businessId) throws BaseException {
        try {
            Map<String, Object> walletInfo = businessWalletMapper.getBusinessWalletInfo(businessId);
            if (walletInfo == null || walletInfo.isEmpty()) {
                throw new ErrorStateException("商家钱包不存在");
            }

            BusinessWalletDTO dto = new BusinessWalletDTO();
            dto.setBusinessId(businessId);
            dto.setBusinessName(getString(walletInfo, "businessName"));

            // 处理金额字段，确保格式正确
            BigDecimal balance = getBigDecimal(walletInfo, "wallet_balance");
            BigDecimal frozen = getBigDecimal(walletInfo, "frozen_amount");
            BigDecimal available = balance.subtract(frozen);

            dto.setWalletBalance(balance.setScale(2, RoundingMode.HALF_UP).toString());
            dto.setFrozenAmount(frozen.setScale(2, RoundingMode.HALF_UP).toString());
            dto.setAvailableBalance(available.setScale(2, RoundingMode.HALF_UP).toString());

            dto.setTotalOrders(getInteger(walletInfo, "total_orders"));
            dto.setTotalRevenue(getBigDecimal(walletInfo, "total_revenue").setScale(2, RoundingMode.HALF_UP).toString());
            dto.setTotalPlatformFee(getBigDecimal(walletInfo, "total_platform_fee").setScale(2, RoundingMode.HALF_UP).toString());

            // 处理时间字段
            if (walletInfo.get("wallet_create_time") != null) {
                dto.setWalletCreateTime(walletInfo.get("wallet_create_time").toString());
            }
            if (walletInfo.get("wallet_update_time") != null) {
                dto.setWalletUpdateTime(walletInfo.get("wallet_update_time").toString());
            }

            return dto;
        } catch (Exception e) {
            log.error("获取商家钱包信息失败: businessId={}, error={}", businessId, e.getMessage());
            throw new ErrorStateException("获取商家钱包信息失败: " + e.getMessage());
        }
    }

    @Override
    public List<BusinessWalletDTO> getAllBusinessWalletInfo() throws BaseException {
        try {
            List<Map<String, Object>> walletInfoList = businessWalletMapper.getAllBusinessWalletInfo();
            List<BusinessWalletDTO> dtoList = new ArrayList<>();

            for (Map<String, Object> walletInfo : walletInfoList) {
                BusinessWalletDTO dto = new BusinessWalletDTO();
                dto.setBusinessId(getString(walletInfo, "businessId"));
                dto.setBusinessName(getString(walletInfo, "businessName"));

                BigDecimal balance = getBigDecimal(walletInfo, "wallet_balance");
                BigDecimal frozen = getBigDecimal(walletInfo, "frozen_amount");
                BigDecimal available = balance.subtract(frozen);

                dto.setWalletBalance(balance.setScale(2, RoundingMode.HALF_UP).toString());
                dto.setFrozenAmount(frozen.setScale(2, RoundingMode.HALF_UP).toString());
                dto.setAvailableBalance(available.setScale(2, RoundingMode.HALF_UP).toString());

                dto.setTotalOrders(getInteger(walletInfo, "total_orders"));
                dto.setTotalRevenue(getBigDecimal(walletInfo, "total_revenue").setScale(2, RoundingMode.HALF_UP).toString());
                dto.setTotalPlatformFee(getBigDecimal(walletInfo, "total_platform_fee").setScale(2, RoundingMode.HALF_UP).toString());

                dtoList.add(dto);
            }

            return dtoList;
        } catch (Exception e) {
            log.error("获取所有商家钱包信息失败: error={}", e.getMessage());
            throw new ErrorStateException("获取所有商家钱包信息失败: " + e.getMessage());
        }
    }

    @Override
    public String processOrderPayment(String userId, String businessId, Integer orderId, 
                                    BigDecimal amount, String payPwd) throws BaseException {
        try {
            // 1. 验证用户钱包和支付密码
            VirtualWallet userWallet = walletMapper.selectById(userId);
            if (userWallet == null) {
                throw new ErrorStateException("用户钱包不存在");
            }

            if (!BCrypt.checkpw(payPwd, userWallet.getPayPwd())) {
                throw new ErrorStateException("支付密码错误");
            }

            // 2. 检查用户余额
            if (userWallet.getBalance().compareTo(amount) < 0) {
                throw new IllegalAmountException("余额不足");
            }

            // 3. 确保商家钱包存在
            VirtualWallet businessWallet = walletMapper.selectById(businessId);
            if (businessWallet == null) {
                initBusinessWallet(businessId);
                businessWallet = walletMapper.selectById(businessId);
            }

            // 4. 计算平台手续费和商家实际收到金额
            BigDecimal platformFee = calculatePlatformFee(amount);
            BigDecimal businessReceived = amount.subtract(platformFee);

            // 5. 生成交易ID
            String transId = String.valueOf(System.currentTimeMillis()) + 
                           String.valueOf((int)(Math.random() * 9 + 1) * 10000);

            // 6. 执行支付流程
            // 扣除用户余额
            userWallet.debit(amount);
            walletMapper.updateById(userWallet);

            // 增加商家余额（扣除手续费后）
            businessWallet.credit(businessReceived);
            walletMapper.updateById(businessWallet);

            // 7. 记录交易流水
            WalletTransaction transaction = new WalletTransaction(userId, businessId, amount);
            transaction.unfreeze(); // 直接解冻，表示交易完成
            walletMapper.addTrans(transaction);

            // 8. 记录平台收益
            PlatformRevenue revenue = new PlatformRevenue(orderId, businessId, userId, 
                                                        amount, platformFee, businessReceived, transId);
            businessWalletMapper.insert(revenue);

            log.info("订单支付成功: orderId={}, userId={}, businessId={}, amount={}, platformFee={}, businessReceived={}", 
                    orderId, userId, businessId, amount, platformFee, businessReceived);

            return transId;
        } catch (BaseException e) {
            throw e;
        } catch (Exception e) {
            log.error("订单支付失败: orderId={}, userId={}, businessId={}, amount={}, error={}", 
                     orderId, userId, businessId, amount, e.getMessage());
            throw new ErrorStateException("支付处理失败: " + e.getMessage());
        }
    }

	/**
	 * 订单退款：从商家钱包退回到用户钱包（仅钱包支付场景）
	 */
	@Override
	public String processOrderRefund(String userId, String businessId, Integer orderId, BigDecimal amount) throws BaseException {
		try {
			// 1. 获取用户钱包
			VirtualWallet userWallet = walletMapper.selectById(userId);
			if (userWallet == null) {
				throw new ErrorStateException("用户钱包不存在");
			}

			// 2. 获取商家钱包
			VirtualWallet businessWallet = walletMapper.selectById(businessId);
			if (businessWallet == null) {
				throw new ErrorStateException("商家钱包不存在");
			}

			// 3. 检查商家余额是否足够退款
			if (businessWallet.getBalance().compareTo(amount) < 0) {
				throw new IllegalAmountException("商家钱包余额不足，无法完成退款");
			}

			// 4. 生成交易ID（沿用 WalletTransaction 的生成规则）
			WalletTransaction transaction = new WalletTransaction(businessId, userId, amount);
			String transId = transaction.getTransId();

			// 5. 执行退款流程：商家扣款，用户收款
			businessWallet.debit(amount);
			walletMapper.updateById(businessWallet);

			userWallet.credit(amount);
			walletMapper.updateById(userWallet);

			// 6. 记录退款交易流水
			transaction.unfreeze();
			walletMapper.addTrans(transaction);

			log.info("订单退款成功: orderId={}, userId={}, businessId={}, amount={} ",
			        orderId, userId, businessId, amount);

			return transId;
		} catch (BaseException e) {
			throw e;
		} catch (Exception e) {
			log.error("订单退款失败: orderId={}, userId={}, businessId={}, amount={}, error={}",
			         orderId, userId, businessId, amount, e.getMessage());
			throw new ErrorStateException("退款处理失败: " + e.getMessage());
		}
	}

    @Override
    public void businessWithdraw(String businessId, String payPwd, BigDecimal amount) throws BaseException {
        try {
            VirtualWallet businessWallet = walletMapper.selectById(businessId);
            if (businessWallet == null) {
                throw new ErrorStateException("商家钱包不存在");
            }

            if (!BCrypt.checkpw(payPwd, businessWallet.getPayPwd())) {
                throw new ErrorStateException("支付密码错误");
            }

            if (businessWallet.getBalance().compareTo(amount) < 0) {
                throw new IllegalAmountException("余额不足");
            }

            // 执行提现
            businessWallet.debit(amount);
            walletMapper.updateById(businessWallet);

            // 记录提现交易
            WalletTransaction transaction = new WalletTransaction(businessId, businessId, amount);
            transaction.unfreeze();
            walletMapper.addTrans(transaction);

            log.info("商家提现成功: businessId={}, amount={}", businessId, amount);
        } catch (BaseException e) {
            throw e;
        } catch (Exception e) {
            log.error("商家提现失败: businessId={}, amount={}, error={}", businessId, amount, e.getMessage());
            throw new ErrorStateException("提现失败: " + e.getMessage());
        }
    }

    @Override
    public Map<String, Object> getTodayRevenueStats(String businessId) throws BaseException {
        try {
            return businessWalletMapper.getTodayRevenueStats(businessId);
        } catch (Exception e) {
            log.error("获取今日收益统计失败: businessId={}, error={}", businessId, e.getMessage());
            throw new ErrorStateException("获取今日收益统计失败: " + e.getMessage());
        }
    }

    @Override
    public Map<String, Object> getMonthlyRevenueStats(String businessId) throws BaseException {
        try {
            return businessWalletMapper.getMonthlyRevenueStats(businessId);
        } catch (Exception e) {
            log.error("获取月度收益统计失败: businessId={}, error={}", businessId, e.getMessage());
            throw new ErrorStateException("获取月度收益统计失败: " + e.getMessage());
        }
    }

    @Override
    public Map<String, Object> getPlatformTotalStats() throws BaseException {
        try {
            return businessWalletMapper.getPlatformTotalStats();
        } catch (Exception e) {
            log.error("获取平台总收益统计失败: error={}", e.getMessage());
            throw new ErrorStateException("获取平台总收益统计失败: " + e.getMessage());
        }
    }

    @Override
    public List<Map<String, Object>> getBusinessTransactions(String businessId, Integer page, Integer size) throws BaseException {
        try {
            Integer offset = (page - 1) * size;
            return businessWalletMapper.getBusinessTransactions(businessId, size, offset);
        } catch (Exception e) {
            log.error("获取商家交易记录失败: businessId={}, error={}", businessId, e.getMessage());
            throw new ErrorStateException("获取商家交易记录失败: " + e.getMessage());
        }
    }

    @Override
    public void initBusinessWallet(String businessId) throws BaseException {
        try {
            VirtualWallet existingWallet = walletMapper.selectById(businessId);
            if (existingWallet != null) {
                return; // 钱包已存在
            }

            // 创建商家钱包，使用默认密码
            String defaultPassword = "123456";
            String encodedPassword = encoder.encode(defaultPassword);
            VirtualWallet businessWallet = new VirtualWallet(businessId, encodedPassword);
            walletMapper.insert(businessWallet);

            log.info("商家钱包初始化成功: businessId={}", businessId);
        } catch (Exception e) {
            log.error("商家钱包初始化失败: businessId={}, error={}", businessId, e.getMessage());
            throw new ErrorStateException("商家钱包初始化失败: " + e.getMessage());
        }
    }

    @Override
    public BigDecimal calculatePlatformFee(BigDecimal orderAmount) {
        // 固定收取1元平台手续费
        return PLATFORM_FEE;
    }

    // 辅助方法
    private String getString(Map<String, Object> map, String key) {
        Object value = map.get(key);
        return value != null ? value.toString() : "";
    }

    private BigDecimal getBigDecimal(Map<String, Object> map, String key) {
        Object value = map.get(key);
        if (value == null) {
            return BigDecimal.ZERO;
        }
        if (value instanceof BigDecimal) {
            return (BigDecimal) value;
        }
        try {
            return new BigDecimal(value.toString());
        } catch (NumberFormatException e) {
            return BigDecimal.ZERO;
        }
    }

    private Integer getInteger(Map<String, Object> map, String key) {
        Object value = map.get(key);
        if (value == null) {
            return 0;
        }
        if (value instanceof Integer) {
            return (Integer) value;
        }
        try {
            return Integer.valueOf(value.toString());
        } catch (NumberFormatException e) {
            return 0;
        }
    }
}
